#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include "head.h"
/*   myirq{
       compatible="myirq";
       interrupt-parent=<&gpiof>;
       interrupts=<12 1>;
   };*/
unsigned int major;
struct class *cls;
struct device *dev;
unsigned int irqno;        // 软中断号
struct device_node *dnode; // 设备树节点对象
struct gpio_desc *gpiono;  // gpio对象
int people_flag;           // 有人标志1

// 定义中断处理函数
irqreturn_t people_handler(int irq, void *dev)
{
    if (gpiod_get_value(gpiono) == 1)
    {
        people_flag = 1;
        // printk("有人,累计%d次\n", count);
    }

    return IRQ_HANDLED;
}

// 封装操作方法
int rda226_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

ssize_t rda226_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
    int ret;
    ret = copy_to_user(ubuf,(void *)&people_flag, 4);
    if (ret)
    {
        printk("copy_to_user err\n");
        return ret;
    }

    return 0;
}

int rda226_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

// 定义操作方法结构体遍历并且初始化
struct file_operations fops = {
    .open = rda226_open,
    .read = rda226_read,
    .release = rda226_close,
};

static int __init mycdev_init(void)
{
    int ret;
    // 字符设备驱动注册
    major = register_chrdev(0, "rda226", &fops);
    if (major < 0)
    {
        printk("注册字符设备驱动失败\n");
        ret = major;
        goto out1;
    }
    printk("注册字符设备驱动成功\n");

    // 设备节点的创建
    // 向上提交目录
    cls = class_create(THIS_MODULE, "rda226");
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        ret = PTR_ERR(cls);
        goto out2;
    }
    printk("向上提交目录成功\n");

    // 向上提交设备节点
    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "rda226");
    if (IS_ERR(dev))
    {
        printk("向上提交设备节点信息失败\n");
        ret = PTR_ERR(dev);
        goto out3;
    }
    printk("向上提交设备节点信息成功\n");

    // 解析人体红外的设备树节点
    dnode = of_find_compatible_node(NULL, NULL, "myirq");
    if (dnode == NULL)
    {
        printk("解析设备树节点失败\n");
        return -ENXIO;
    }
    printk("解析设备树节点成功\n");

    // 申请gpio对象
    gpiono = gpiod_get_from_of_node(dnode, "rda226", 0, GPIOD_IN, NULL);
    if (IS_ERR(gpiono))
    {
        printk("申请gpio对象失败\n");
        return -ENXIO;
    }
    printk("申请gpio信息对象成功\n");

    printk("解析设备树节点成功\n");
    // 解析人体红外的软中断号
    irqno = irq_of_parse_and_map(dnode, 0);
    if (!irqno)
    {
        printk("解析人体红外软中断号失败\n");
        return -ENXIO;
    }
    printk("解析人体红外软中断号成功%d\n", irqno);

    // 注册 人体红外中断
    int res = request_irq(irqno, people_handler, IRQF_TRIGGER_HIGH, "rda226", NULL);
    if (res < 0)
    {
        printk("注册人体红外中断失败\n");
        return ret;
    }
    printk("注册人体红外中断成功\n");

    return 0;
out3:
    class_destroy(cls);
out2:
    unregister_chrdev(major, "rda226");
out1:
    return ret;
}
static void __exit mycdev_exit(void)
{
    // 注销中断
    free_irq(irqno, NULL);

    // 释放gpio对象
    gpiod_put(gpiono);

    // 设备节点的销毁
    device_destroy(cls, MKDEV(major, 0));
    // 设备信息的注销
    class_destroy(cls);
    // 字符设备驱动注销
    unregister_chrdev(major, "rda226");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");